from typing import List, Optional, Dict, Any, Tuple
from datetime import datetime
import uuid
from models import PromptItem, Category, PromptUtils, DEFAULT_CATEGORIES
from storage import StorageManager


class PromptManager:
    """提示词管理器核心类"""
    
    def __init__(self, data_dir: str = "data"):
        """初始化提示词管理器
        
        Args:
            data_dir: 数据存储目录
        """
        self.storage = StorageManager(data_dir)
        self._prompts_cache: Optional[List[PromptItem]] = None
        self._categories_cache: Optional[List[Category]] = None
    
    def _load_prompts(self, force_reload: bool = False) -> List[PromptItem]:
        """加载提示词（带缓存）"""
        if self._prompts_cache is None or force_reload:
            self._prompts_cache = self.storage.load_prompts()
        return self._prompts_cache
    
    def _load_categories(self, force_reload: bool = False) -> List[Category]:
        """加载分类（带缓存）"""
        if self._categories_cache is None or force_reload:
            self._categories_cache = self.storage.load_categories()
        return self._categories_cache
    
    def _save_prompts(self, prompts: List[PromptItem]) -> bool:
        """保存提示词并更新缓存"""
        prompts_data = [prompt.to_dict() for prompt in prompts]
        success = self.storage.save_prompts(prompts_data)
        if success:
            self._prompts_cache = prompts
        return success
    
    def _save_categories(self, categories: List[Category]) -> bool:
        """保存分类并更新缓存"""
        categories_data = [category.to_dict() for category in categories]
        success = self.storage.save_categories(categories_data)
        if success:
            self._categories_cache = categories
        return success
    
    # ==================== 提示词管理 ====================
    
    def add_prompt(self, title: str, content: str, tags: Optional[List[str]] = None, 
                   category_id: str = "default", enabled: bool = True) -> Optional[PromptItem]:
        """添加新提示词
        
        Args:
            title: 提示词标题
            content: 提示词内容
            tags: 标签列表
            category_id: 分类ID
            enabled: 是否启用
            
        Returns:
            Optional[PromptItem]: 创建的提示词对象，失败时返回None
        """
        try:
            if not title.strip() or not content.strip():
                print("标题和内容不能为空")
                return None
            
            # 生成唯一ID
            prompt_id = PromptUtils.generate_prompt_id(title, content, tags)
            
            # 检查ID是否已存在
            existing_prompts = self._load_prompts()
            if any(prompt.id == prompt_id for prompt in existing_prompts):
                print(f"提示词已存在: {title}")
                return None
            
            # 验证分类是否存在
            categories = self._load_categories()
            if not any(cat.id == category_id for cat in categories):
                print(f"分类不存在: {category_id}，使用默认分类")
                category_id = "default"
            
            # 创建新提示词
            new_prompt = PromptItem(
                id=prompt_id,
                title=title.strip(),
                content=content.strip(),
                tags=tags or [],
                enabled=enabled,
                category_id=category_id
            )
            
            # 添加到列表并保存
            prompts = existing_prompts + [new_prompt]
            if self._save_prompts(prompts):
                print(f"提示词添加成功: {title}")
                return new_prompt
            else:
                print(f"提示词保存失败: {title}")
                return None
                
        except Exception as e:
            print(f"添加提示词失败: {e}")
            return None
    
    def get_prompt_by_id(self, prompt_id: str) -> Optional[PromptItem]:
        """根据ID获取提示词"""
        prompts = self._load_prompts()
        return next((prompt for prompt in prompts if prompt.id == prompt_id), None)
    
    def update_prompt(self, prompt_id: str, title: Optional[str] = None, 
                     content: Optional[str] = None, tags: Optional[List[str]] = None,
                     category_id: Optional[str] = None, enabled: Optional[bool] = None) -> bool:
        """更新提示词
        
        Args:
            prompt_id: 提示词ID
            title: 新标题
            content: 新内容
            tags: 新标签列表
            category_id: 新分类ID
            enabled: 新启用状态
            
        Returns:
            bool: 更新是否成功
        """
        try:
            prompts = self._load_prompts()
            prompt_index = next((i for i, p in enumerate(prompts) if p.id == prompt_id), -1)
            
            if prompt_index == -1:
                print(f"提示词不存在: {prompt_id}")
                return False
            
            # 更新字段
            prompt = prompts[prompt_index]
            if title is not None:
                prompt.title = title.strip()
            if content is not None:
                prompt.content = content.strip()
                # 重新提取变量
                prompt.variables = prompt.extract_variables()
            if tags is not None:
                prompt.tags = tags
            if category_id is not None:
                # 验证分类是否存在
                categories = self._load_categories()
                if any(cat.id == category_id for cat in categories):
                    prompt.category_id = category_id
                else:
                    print(f"分类不存在: {category_id}，保持原分类")
            if enabled is not None:
                prompt.enabled = enabled
            
            # 保存更新
            if self._save_prompts(prompts):
                print(f"提示词更新成功: {prompt.title}")
                return True
            else:
                print(f"提示词更新失败: {prompt.title}")
                return False
                
        except Exception as e:
            print(f"更新提示词失败: {e}")
            return False
    
    def delete_prompt(self, prompt_id: str) -> bool:
        """删除提示词
        
        Args:
            prompt_id: 提示词ID
            
        Returns:
            bool: 删除是否成功
        """
        try:
            prompts = self._load_prompts()
            original_count = len(prompts)
            
            # 过滤掉要删除的提示词
            prompts = [prompt for prompt in prompts if prompt.id != prompt_id]
            
            if len(prompts) == original_count:
                print(f"提示词不存在: {prompt_id}")
                return False
            
            if self._save_prompts(prompts):
                print(f"提示词删除成功: {prompt_id}")
                return True
            else:
                print(f"提示词删除失败: {prompt_id}")
                return False
                
        except Exception as e:
            print(f"删除提示词失败: {e}")
            return False
    
    def search_prompts(self, query: str = "", category_id: Optional[str] = None,
                      tags: Optional[List[str]] = None, enabled_only: bool = False, disabled_only: bool = False) -> List[PromptItem]:
        """搜索提示词
        
        Args:
            query: 搜索关键词（在标题、内容中搜索）
            category_id: 分类ID过滤
            tags: 标签过滤
            enabled_only: 是否只返回启用的提示词
            disabled_only: 是否只返回禁用的提示词
            
        Returns:
            List[PromptItem]: 匹配的提示词列表
        """
        prompts = self._load_prompts()
        
        # 过滤条件
        filtered_prompts = prompts
        
        # 按启用状态过滤
        if enabled_only:
            filtered_prompts = [p for p in filtered_prompts if p.enabled]
        elif disabled_only:
            filtered_prompts = [p for p in filtered_prompts if not p.enabled]
        
        # 按分类过滤
        if category_id:
            filtered_prompts = [p for p in filtered_prompts if p.category_id == category_id]
        
        # 按标签过滤
        if tags:
            filtered_prompts = [p for p in filtered_prompts 
                              if any(tag in p.tags for tag in tags)]
        
        # 按关键词搜索
        if query.strip():
            query_lower = query.lower().strip()
            filtered_prompts = [p for p in filtered_prompts 
                              if (query_lower in p.title.lower() or 
                                  query_lower in p.content.lower() or 
                                  any(query_lower in tag.lower() for tag in p.tags))]
        
        return filtered_prompts
    
    def get_all_prompts(self) -> List[PromptItem]:
        """获取所有提示词"""
        return self._load_prompts()
    
    def toggle_prompt_enabled(self, prompt_id: str) -> bool:
        """切换提示词启用状态"""
        prompt = self.get_prompt_by_id(prompt_id)
        if prompt:
            return self.update_prompt(prompt_id, enabled=not prompt.enabled)
        return False
    
    # ==================== 分类管理 ====================
    
    def add_category(self, name: str, description: Optional[str] = None, 
                    color: Optional[str] = None) -> Optional[Category]:
        """添加新分类
        
        Args:
            name: 分类名称
            description: 分类描述
            color: 分类颜色
            
        Returns:
            Optional[Category]: 创建的分类对象，失败时返回None
        """
        try:
            if not name.strip():
                print("分类名称不能为空")
                return None
            
            categories = self._load_categories()
            
            # 检查名称是否已存在
            if any(cat.name.lower() == name.lower().strip() for cat in categories):
                print(f"分类名称已存在: {name}")
                return None
            
            # 创建新分类
            new_category = Category(
                id=str(uuid.uuid4()),
                name=name.strip(),
                description=description,
                color=color
            )
            
            # 添加到列表并保存
            categories.append(new_category)
            if self._save_categories(categories):
                print(f"分类添加成功: {name}")
                return new_category
            else:
                print(f"分类保存失败: {name}")
                return None
                
        except Exception as e:
            print(f"添加分类失败: {e}")
            return None
    
    def get_category_by_id(self, category_id: str) -> Optional[Category]:
        """根据ID获取分类"""
        categories = self._load_categories()
        return next((cat for cat in categories if cat.id == category_id), None)
    
    def update_category(self, category_id: str, name: Optional[str] = None,
                       description: Optional[str] = None, color: Optional[str] = None,
                       enabled: Optional[bool] = None) -> bool:
        """更新分类
        
        Args:
            category_id: 分类ID
            name: 新名称
            description: 新描述
            color: 新颜色
            enabled: 新启用状态
            
        Returns:
            bool: 更新是否成功
        """
        try:
            categories = self._load_categories()
            category_index = next((i for i, c in enumerate(categories) if c.id == category_id), -1)
            
            if category_index == -1:
                print(f"分类不存在: {category_id}")
                return False
            
            # 更新字段
            category = categories[category_index]
            if name is not None:
                # 检查新名称是否与其他分类重复
                if any(cat.name.lower() == name.lower().strip() and cat.id != category_id 
                      for cat in categories):
                    print(f"分类名称已存在: {name}")
                    return False
                category.name = name.strip()
            if description is not None:
                category.description = description
            if color is not None:
                category.color = color
            if enabled is not None:
                category.enabled = enabled
            
            category.updated_at = datetime.now().isoformat()
            
            # 保存更新
            if self._save_categories(categories):
                print(f"分类更新成功: {category.name}")
                return True
            else:
                print(f"分类更新失败: {category.name}")
                return False
                
        except Exception as e:
            print(f"更新分类失败: {e}")
            return False
    
    def delete_category(self, category_id: str) -> bool:
        """删除分类（将其下的提示词移动到默认分类）
        
        Args:
            category_id: 分类ID
            
        Returns:
            bool: 删除是否成功
        """
        try:
            if category_id == "default":
                print("不能删除默认分类")
                return False
            
            categories = self._load_categories()
            category_index = next((i for i, c in enumerate(categories) if c.id == category_id), -1)
            
            if category_index == -1:
                print(f"分类不存在: {category_id}")
                return False
            
            # 将该分类下的提示词移动到默认分类
            prompts = self._load_prompts()
            updated_prompts = []
            for prompt in prompts:
                if prompt.category_id == category_id:
                    prompt.category_id = "default"
                updated_prompts.append(prompt)
            
            # 删除分类
            categories.pop(category_index)
            
            # 保存更新
            success = True
            success &= self._save_prompts(updated_prompts)
            success &= self._save_categories(categories)
            
            if success:
                print(f"分类删除成功: {category_id}")
                return True
            else:
                print(f"分类删除失败: {category_id}")
                return False
                
        except Exception as e:
            print(f"删除分类失败: {e}")
            return False
    
    def get_all_categories(self) -> List[Category]:
        """获取所有分类"""
        return self._load_categories()
    
    def get_prompt_count_by_category(self, category_id: str) -> int:
        """获取指定分类下的提示词数量"""
        prompts = self._load_prompts()
        return sum(1 for prompt in prompts if prompt.category_id == category_id)
    
    # ==================== 标签管理 ====================
    
    def get_all_tags(self) -> List[str]:
        """获取所有标签"""
        prompts = self._load_prompts()
        tags = set()
        for prompt in prompts:
            tags.update(prompt.tags)
        return sorted(list(tags))
    
    def get_tag_usage_stats(self) -> Dict[str, int]:
        """获取标签使用统计"""
        prompts = self._load_prompts()
        tag_stats = {}
        for prompt in prompts:
            for tag in prompt.tags:
                tag_stats[tag] = tag_stats.get(tag, 0) + 1
        return tag_stats
    
    def rename_tag(self, old_tag: str, new_tag: str) -> bool:
        """重命名标签
        
        Args:
            old_tag: 旧标签名
            new_tag: 新标签名
            
        Returns:
            bool: 重命名是否成功
        """
        try:
            if not old_tag.strip() or not new_tag.strip():
                print("标签名不能为空")
                return False
            
            prompts = self._load_prompts()
            updated = False
            
            for prompt in prompts:
                if old_tag in prompt.tags:
                    prompt.tags = [new_tag if tag == old_tag else tag for tag in prompt.tags]
                    updated = True
            
            if updated:
                if self._save_prompts(prompts):
                    print(f"标签重命名成功: {old_tag} -> {new_tag}")
                    return True
                else:
                    print(f"标签重命名失败: {old_tag} -> {new_tag}")
                    return False
            else:
                print(f"未找到标签: {old_tag}")
                return False
                
        except Exception as e:
            print(f"重命名标签失败: {e}")
            return False
    
    def delete_tag(self, tag: str) -> bool:
        """删除标签（从所有提示词中移除）
        
        Args:
            tag: 要删除的标签
            
        Returns:
            bool: 删除是否成功
        """
        try:
            prompts = self._load_prompts()
            updated = False
            
            for prompt in prompts:
                if tag in prompt.tags:
                    prompt.tags = [t for t in prompt.tags if t != tag]
                    updated = True
            
            if updated:
                if self._save_prompts(prompts):
                    print(f"标签删除成功: {tag}")
                    return True
                else:
                    print(f"标签删除失败: {tag}")
                    return False
            else:
                print(f"未找到标签: {tag}")
                return False
                
        except Exception as e:
            print(f"删除标签失败: {e}")
            return False
    
    # ==================== 导入导出 ====================
    
    def export_prompts(self, export_path: str) -> bool:
        """导出提示词到文件"""
        return self.storage.export_data(export_path)
    
    def export_single_prompt(self, prompt_id: str, export_path: str) -> bool:
        """导出单个提示词到文件"""
        prompt = self.get_prompt_by_id(prompt_id)
        if not prompt:
            return False
        
        try:
            from datetime import datetime
            import json
            
            export_data = {
                'prompt': prompt.to_dict(),
                'export_time': datetime.now().isoformat(),
                'version': '1.0'
            }
            
            with open(export_path, 'w', encoding='utf-8') as f:
                json.dump(export_data, f, ensure_ascii=False, indent=2)
            
            return True
        except Exception as e:
            print(f"导出单个提示词失败: {e}")
            return False
    
    def import_prompts(self, import_path: str, merge: bool = True) -> bool:
        """从文件导入提示词"""
        success = self.storage.import_data(import_path, merge)
        if success:
            # 清除缓存，强制重新加载
            self._prompts_cache = None
            self._categories_cache = None
        return success
    
    def backup_data(self, backup_dir: str = "backups") -> Optional[str]:
        """备份数据"""
        return self.storage.backup_data(backup_dir)
    
    # ==================== 统计信息 ====================
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取统计信息"""
        prompts = self._load_prompts()
        categories = self._load_categories()
        
        # 基本统计
        total_prompts = len(prompts)
        enabled_prompts = sum(1 for p in prompts if p.enabled)
        disabled_prompts = total_prompts - enabled_prompts
        
        # 分类统计
        category_stats = {}
        category_info = []
        for category in categories:
            count = sum(1 for p in prompts if p.category_id == category.id)
            category_stats[category.name] = {
                'count': count,
                'enabled': category.enabled
            }
            category_info.append({
                'category': category,
                'count': count
            })
        
        # 标签统计
        tag_stats = self.get_tag_usage_stats()
        
        # 变量统计
        variable_stats = {}
        for prompt in prompts:
            if prompt.variables:
                for var in prompt.variables:
                    variable_stats[var] = variable_stats.get(var, 0) + 1
        
        return {
            'total_prompts': total_prompts,
            'enabled_prompts': enabled_prompts,
            'disabled_prompts': disabled_prompts,
            'total_categories': len(categories),
            'category_stats': category_stats,
            'category_info': category_info,
            'total_tags': len(tag_stats),
            'tag_stats': tag_stats,
            'total_variables': len(variable_stats),
            'variable_stats': variable_stats,
            'storage_stats': self.storage.get_storage_stats()
        }